/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

class MyPromise{
    statusObj = {
        pending:'pending',
        success:'fulfilled',
        error:'rejected'
    }
    // 状态；
    status = undefined
    // 成功时存储的值；
    successData = undefined
    // 失败时 存储的值；
    errorData = undefined
    // 链式调用中，储存的成功回调函数集合
    _successCallbackList = []
    // 链式调用，储存的失败回调函数集合；
    _errorCallbackList = []
    constructor(fn){
        this.status = this.statusObj.pending;
        fn(this.resolve.bind(this),this.reject.bind(this));
    }
   
    resolve(params){
        if(this.status !== this.statusObj.pending) return  // 如果状态不是等待了，不需要往下执行； 
        this.status = this.statusObj.success; // 更改状态；
        this.successData = params; // 存储成功值
        while(this._successCallbackList.length){ // 按照储存的成功回调的集合数据，依次调用函数；
            this._successCallbackList.shift()();
        }
    }
    reject(reason){
        // return ;
        if(this.status !== this.statusObj.pending) return // 如果状态不是等待了，不需要往下执行； 
        this.status = this.statusObj.error; // 更改状态；
        this.errorData = reason;// 存储失败值
        while(this._errorCallbackList.length){// 按照储存的失败回调的集合数据，依次调用函数；
            this._errorCallbackList.shift()();
        }
    }
    static resolve(value){
        if( value instanceof MyPromise){
            return value
        } else {
            return new MyPromise((resolve)=>resolve(value))
        }
    }
    static reject(value){
        if( value instanceof MyPromise){
            return value;
        } else {
            return new MyPromise((undefined,resolve)=>resolve(value))
        }
    }
    static all(list=[]){
        return new MyPromise((resolve,reject)=>{
            const res = [];
            function add(item) {
                res.push(item);
                if(res.length === list.length ){
                    resolve(res);
                }
            }
            function fail(params) {
                reject(params)
            }
            if(Array.isArray(list)){
                list.forEach(item=>{
                    if(item instanceof MyPromise){
                        item.then(add,fail)
                    } else {
                        res.push(item);
                    }
                })
            }
        })
    }
    // 无论成功或者失败都会调用的方法；
    // 调用是在resolve，reject函数之前的；
    finally(fn){
            return this.then(v=>{
                return MyPromise.resolve(fn()).then(()=>v);
            },e=>{
                return MyPromise.reject(fn()).then(undefined,a=>{throw e });
            })
        
    }
    // 获取报错信息的方法；
    catch(fn){
        this.then(undefined,fn)
    }
    then(successCallback,errorCallback){
        const p1 =  new MyPromise((resolve,reject)=>{
            // 处理fulFilled状态的函数；
            const  resolveFn = ()=>{
                var x = undefined;
                if(successCallback) { // 如果有成功回调则使用；
                    x = successCallback(this.successData)
                } 
                this.dealReturnDataFn(p1,x,resolve,reject)
            }
            // 处理失败状态的函数；
            const rejectFn = ()=>{
                var y = undefined;
                if(errorCallback) { // 如果有失败回调则使用；
                    y = errorCallback(this.errorData)

                } 

                this.dealReturnDataFn(p1,y,resolve,reject)
            }
            if( this.status === this.statusObj.success ){
                // 因为传递的P1有可能是正在执行还没有得到p1，使用异步调用一下；
                setTimeout(resolveFn,0)
                
            } else if( this.status === this.statusObj.error ) {
                // 因为传递的P1有可能是正在执行还没有得到p1，使用异步调用一下；

                setTimeout(rejectFn,0)
            } else {
                this._successCallbackList.push(resolveFn)
                this._errorCallbackList.push(rejectFn)
            }
            
        })
        return p1
    }
    // 处理返回值；
    dealReturnDataFn(p2,res,resolve,reject){
        if( p2 === res ){
            console.log(p2,res,'same error');
            console.log(new Error('asdfasdf'))
        }
        if(res instanceof MyPromise){
            res.then(resolve,reject);
        } else if( this.status === this.statusObj.success ){
            resolve(res);
        } else if( this.status === this.statusObj.error ){
            reject(res);
        }
    }
}

console.log('start promise')


function testThan(p){

    p.then(s=>{
        console.log(s);
        return 1
    },e=>{
        console.log(e);
    })
    .then(v=>{
        console.log(v);
        return new MyPromise((resolve)=>{
            setTimeout(v=>resolve(2))
        })
    })
    .then(v=>{
        console.log(v);
    })
}
// testThan(getP(1))
function getP(value,isFail) {
    return new MyPromise((resolve,reject)=>{
        setTimeout(v=>{
            if(isFail){
                reject( value +' error' )
            }
            resolve( value + ' sucess' );
            
        },1000)
        
    })
}

function testResolve(params) {
    MyPromise.resolve(1).then(console.log);
    MyPromise.resolve(getP(2)).then(console.log);
}
// testResolve();
function testReject(params) {
    setTimeout(v=>{
        MyPromise.reject(1).then(undefined,console.log);
        MyPromise.reject(getP(2,true)).then(undefined,console.log);
    })
}
// testReject();

function testAll(params) {
    var arr = [];
    while(arr.length < 5){
        arr.push(getP(arr.length))
    }
    MyPromise.all(arr).then(console.log,console.log)
}

// testAll();

function testFinallyFn(params) {
    getP(1).finally(v=>{
        console.log('finally')
    }).then(
        console.log
    ,console.log)
}
// testFinallyFn();

function testCatchFn(params) {
    getP(1,true).catch(console.log)
}
// testCatchFn();

console.log('end')